#include <string>
#include <inttypes.h>

#include "avr.h"

void AVR::reset ()
{
  _core->reset ();

  for (int i = 0; i < 32; ++i)
    (*_regs)[i] = 0;
}

void AVR::run ()
{
}

void AVR::stop ()
{
}

void AVR::step ()
{
  _clock->tick ();
}

void AVR::load_flash (istream& is)
{
  is.seekg (0, ios::beg);

  while (!is.eof ()) {
    string line;
    getline (is, line);

    string::iterator beg = line.begin ();
    string::iterator end = line.end ();

    if (*beg != ':')
      continue;
    ++beg;

    string str;
    int byte_cnt = -1;
    uint16_t addr = 0xffff;
    int type = -1;
    int cnt = 0;
    for (int i = 0; beg != end; ++beg, ++i) {
      str += *beg;

      if (i == 1) {
        istringstream ss (str);
        ss >> hex >> byte_cnt;
        str.clear ();
      }
      else if (i == 5) {
        istringstream ss (str);
        ss >> hex >> addr;
        str.clear ();
      }
      else if (i == 7) {
        istringstream ss (str);
        ss >> hex >> type;
        str.clear ();
        if (type != 0)
          break;
      }
      else if ((i > 7) && ((i - 7) % 4 == 0)) {
        istringstream ss (str);
        uint16_t s;
        ss >> hex >> s;
        str.clear ();
        s = ((uint16_t)((s & 0xff) << 8)) | ((uint16_t)s >> 8);
        (*_flash)[addr + cnt] = s;
        ++cnt;

        if (cnt * 2 >= byte_cnt)
          break;
      }
    }
  }
}

void AVR::dump_core_status (ostream& os)
{
  ios::fmtflags flgs = os.flags ();

  _core->dump_status (os);

  os.flags (flgs);
}

void AVR::dump_registers (ostream& os)
{
  ios::fmtflags flgs = os.flags ();

  os << "Registers:" << endl;

  for (int i = 0; i < 32; ++i) {
    os << dec << "R";
    os.width (2);
    os.setf (ios::left);
    os << i << ": 0x";
    os.width (3);
    os.setf (ios::left);
    os << hex << (int)(*_regs)[i];

    if (i % 4 == 7)
      os << endl;
  }

  os << endl;

  os.flags (flgs);
}

void AVR::dump_dmem (uint8_t* buff, uint16_t addr, uint16_t cnt)
{
  for (int i = 0; i < cnt; ++i)
    buff[i] = (*_sram)[addr + i];
}

void AVR::dump_pmem (uint16_t* buff, uint16_t addr, uint16_t cnt)
{
  for (int i = 0; i < cnt; ++i)
    buff[i] = (*_flash)[addr + i];
}

void AVR::execute_instruction (uint16_t instruction)
{
  _core->execute_instruction (instruction);
}
